오늘 한 일
- Android 앱개발
- 비동기처리 공부
Coroutine 사용
코루틴이란
: 비동기처리를 위해 사용되는 개념
협력형 멀티태스킹
Co = 협력 routine = 태스크 ⇒ 협력해서 "태스크"를 처리하는 것
Routine이란?
- Main Routine
- Sub Routine
*일반적 매커니즘 with Routines
메인루틴 →[ 서브루틴 호출 → 서브루틴 실행 → 서브루틴 탈출 ]→ 메인루틴
⇒ System Stack에 서브루틴이 push 되어 스레드가 block되어 처리된다
⇒ 서브루틴 호출, 서브루틴 탈출은 오직 한 번 발생한다
*with CoRoutines
메인루틴 → 서브루틴 호출 → 서브루틴 실행 → 서브루틴 탈출 → 메인루틴 실행 → … → 서브루틴 호출 → 서브루틴 탈출…
⇒ 서브루틴 호출, 서브루틴 탈출이 한 태스크 내에서 여러 번 발생할 수 있다
⇒ OS의 인터럽트 개념과 너무 비슷하다
Coroutine 적용
fun subRoutine(){
startCoroutine{
fun1()
fun2()
...
}
}
suspend fun fun1(){}
suspend fun fun2(){}
함수 생성시 코루틴 블록 생성
탈출: return, suspend 함수 호출
호출: 서브루틴 호출, suspend 함수 종료
동시성 프로그래밍
: Coroutine은 병렬성보단 동시성에 더 가깝다
동시성 프로그래밍이란?
멀티태스킹: 와리가리 ↔ 병렬성 프로그래밍: 2배럭
⇒ 유휴시간동안 다른 프로그램 코드가 실행되도록 처리한다.
⇒ 동시성이므로 병렬프로그램과 달리 순서가 지켜진다
부수적인 내용이해
코루틴이 callback 지옥을 막는다는 이유?
“시간이 걸리는” 작업을 할 때, 순차작업의 경우 이전 작업을 기다려야한다.
기다린다 라는 것을 생으로 구현하면 완료시 넘겨준다는 것을 처리하기 위해서 콜백함수를 사용해야함을 의미한다.
fun1(... , fun2(... , fun3(... , fun4()))){}
fun1
의 작업을 끝내고fun2
를 실행하기 위해서callback(fun2)
을 넘겨주며fun1
의 마지막에fun2
를 실행한다
위의 내용이 반복된다…..
따라서 코루틴을 사용하면 콜백 안의 콜백 안의 콜백 .... 이라는 지옥을 벗어날 수 있다
Context & Builder
- CoroutineContext: Coroutine을 실행할 스레드 풀 Dispatcher.Main : UI를 구성하는 작업이 모여있는 쓰레드 풀
Dispatcher.IO : (파일 혹은 소켓을) 읽고 쓰는 작업이 모여있는 쓰레드 풀
Dispatcher.Default : 기본 쓰레드 풀, CPU 사용량이 많은 작업에 적합
CoroutineContext init: context 지정
Dispatchers.Main
CoroutineScope: Coroutine 블록의 scope, Coroutine 제어영역
사용자 지정 scope
val scope = CoroutineScope(Dispatchers.Main)
→ scope 지정 가능하므로, Activity의 lifecycle과 연계가능
global scope → 앱 전체에서 맥락을 가지므로, 장시간 or 주기적으로 실행되어야하는 routine에 적합
CoroutineBuilder: 설정값을 토대로 coroutine을 실행시키는 함수
val job = scope.launch{}
→
Job
,Deferred
로 코루틴 제어가능
비동기처리와 코루틴에 대하여
동기/비동기 & block/nonblock 정리
: 둘을 보는 관점을 명확하게 정리해보고자..
유비추론으로 표현하면, thread와 task의 관계와 같다(like Multithread vs Multitasking)
동기/비동기
: 순차적관점 in thread
: 컴퓨터가 수행할 수 있는 가장 작은 작업의 단위인 thread의 순서결정여부가 지표
blocking/nonblocking
: 순차적관점 in task
: 보다 더 추상화된 계층에서의 작업단위인 task의 순서결정여부가 지표
용어정리
가장 작은 작업 단위
= 컴퓨터 자원을 정확히 1개 사용하는 작업의 단위
(ex 파일저장
은 가장 작은 단위가 아님 = 1.“메모리”에서 데이터를 읽어서 2.“디스크”로 데이터를 써야하는 작업)
프로그래밍 언어 차원에서 가장 작은 단위
: 프로그래밍 언어가 어셈블리어가 아닌 이상 당연히 언어차원에서는 ‘가장 작은 단위’의 작업을 수행할 수 없다. 따라서 프로그래밍 언어 입장에서 자원을 쓰는 가장 작은 단위가 될 것임. 쉽게 말하면 짤 수 있는 가장 로우레벨의 코드 = 강주혁이 맨날 말하는 순수함수?는 아니긴한데 그처럼 가장 로우레벨에 있을 작업
회원가입 요청함수 = 가장 작은 단위 X
ID가 중복되는지 DB로 확인해서 bool 값을 반환하는 함수 = 가장 작은 단위 X
id
값을 인자로 하는 SQL 쿼리 함수 = 가장 작은 단위 O
blocking
: 순차 보장 = 하나의 작업을 마쳐야만 다른 작업 수행가능
= 스레드가 종료되기 전까지 문맥교환이 일어날 수 없다
nonblocking
: 순차 보장 X = 하나의 작업을 마치지 않아도 다른 작업 수행가능
동기/비동기 by callback
: “컴퓨터가 수행할 수 있는 가장 작은 작업의 단위인 thread의 순서결정여부가 지표”라는 말을 이해하기 위해 callback과 System Stack으로 이해해보자
fun parent(){
child()
}
→ System Stack은 child()
를 만나서 child 맥락이 push 됨
→ 문맥이 child 프로시저에 있으므로 child가 시스템 스택 사용을 마치고 반환해야만 parent가 실행가능
→ parent는 System Stack에 의해 blocking 당함 = 동기처리
— 만약 이 때 child()가 자체적으로 실행 중간에 parent로 맥락을 바꿔 진행하다 다시 child로 맥락을 바꾸게 할 수만 있다면 이는 blocking 된 것이 아니므로 단일스레드 내에서 비동기적 처리처럼 보이게 동작한다고 볼 수 있음(실제론 동시성 프로그래밍이지만) = 코루틴
fun parent(child: () -> Unit){
child()
}
→ callback을 통해서 비동기함수는 System Stack이 child()
맥락으로 점프하지 않는다
→ 문맥이 여전히 parent 프로시저에 있음
→ parent는 System Stack에 있지 않으므로 blocking 당하지 않음 = 비동기처리
→ 비동기 처리를 이용하면 시스템 스택이 push 되어 parent()
가 블록되지 않으므로 스레드가 순차적으로 실행될 필요가 없음을 의미
blocking asynchronous 예시
ID가 중복되는지 DB로 확인해서 bool 값을 반환하는 함수
blocking :: id값 확인 → id값으로 쿼리요청 → 쿼리 확인 후 리턴값 설정
비동기처리 :: “id값으로 쿼리요청”이라는 비동기함수를 포함하므로 비동기처리로 볼 수 있음
nonblocking asynchronous 예시
난수로 생성한 10개의 ID 값으로 이벤트 당첨자 닉네임을 10개를 뽑는 함수
nonblocking :: id값으로 닉네임 쿼리요청1~10 모두 독립적, 순서가 상관이 없음
비동기처리 :: “id값으로 닉네임 쿼리요청”이라는 비동기함수를 포함하므로 비동기처리로 볼 수 있음